package com.sta.oldman.tcp;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

/**
 * @author: LunBoWang
 * @description: LimWebSocketServer 类用于启动 WebSocket 服务器。
 * 该类包含一个构造函数，用于初始化服务器的配置和事件循环组。
 * 该类还包含一个 start 方法，用于启动服务器。
 * 该类还包含一个 stop 方法，用于停止服务器。
 * @date: 2025/3/26 下午6:41
 * @version: 1.0
 */

public class LimWebSocketServer {
    NioEventLoopGroup mainGroup;
    NioEventLoopGroup subGroup;
    ServerBootstrap server;

    public LimWebSocketServer() {
        // 初始化主事件循环组，用于处理客户端连接
        mainGroup = new NioEventLoopGroup(20);
        // 初始化子事件循环组，用于处理网络读写
        subGroup = new NioEventLoopGroup(20);
        // 创建一个 ServerBootstrap 实例，用于启动服务器
        server = new ServerBootstrap();
        // 配置主事件循环组和子事件循环组
        server.group(mainGroup, subGroup)
                // 指定使用 NioServerSocketChannel 作为服务器通道
                .channel(NioServerSocketChannel.class)
                // 设置服务器端的 backlog 队列大小
                .option(ChannelOption.SO_BACKLOG, 10240)
                // 允许地址重用
                .option(ChannelOption.SO_REUSEADDR, true)
                // 禁用 Nagle 算法，减少延迟 简单点说是否批量发送数据 true关闭 false开启。 开启的话可以减少一定的网络开销，但影响消息实时性
                .childOption(ChannelOption.TCP_NODELAY, true)
                // 启用 TCP 保持活动状态 保活开关2h没有数据服务端会发送心跳包
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                // 为每个新连接的通道添加一个 ChannelInitializer
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        // websocket 基于http协议，所以要有http编解码器
                        pipeline.addLast("http-codec", new HttpServerCodec());
                        // 对写大数据流的支持
                        pipeline.addLast("http-chunked", new ChunkedWriteHandler());
                        // 几乎在netty中的编程，都会使用到此hanler
                        pipeline.addLast("aggregator", new HttpObjectAggregator(65535));
                        /*
                         * websocket 服务器处理的协议，用于指定给客户端连接访问的路由 : /ws
                         * 本handler会帮你处理一些繁重的复杂的事
                         * 会帮你处理握手动作： handshaking（close, ping, pong） ping + pong = 心跳
                         * 对于websocket来讲，都是以frames进行传输的，不同的数据类型对应的frames也不同
                         */
                        pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
//                        pipeline.addLast(new WebSocketMessageDecoder());
//                        pipeline.addLast(new WebSocketMessageEncoder());
                        pipeline.addLast(new NettyServerHandler());
                    }
                });
    }

    public void start() {
        this.server.bind(8082);
    }
}
